#title: 如何创建 DataSource
#author:zozoh(zozohtnt@gmail.com)
#author:wendal(wendal1985@gmail.com)
#index:0,1
--------------------------------------------------------------------------------------
何为DataSource

	先看看JDK中对DataSource的描述:
		* 作为 DriverManager 工具的替代项，DataSource 对象是获取连接的首选方法。
		* 基本实现 - 生成标准的 Connection 对象
		* 连接池实现 - 生成自动参与连接池的 Connection 对象。此实现与中间层连接池管理器一起使用。
		
	简单来说,就是获取数据库连接的一个通用接口, 常见的dbcp,c3p0,druid,bonecp都是DataSource的实现.
	
	NutDao也选用DataSource作为获取数据库连接的方式, 且只调用其无参数的getConnection()方法,
	也是大部分数据库连接池唯一支持的方法.
	
--------------------------------------------------------------------------------------
这篇文档该怎么用?

	直接书写 Java 代码 
		* 如果你只是在main方法中尝试一下NutDao的功能,那么请选取Java
		
	通过 Nutz.Ioc 的 JSON 配置文件
		* Nutz项目中最常见的配置方式, 由NutIoc来管理DataSource和NutDao实例
		* 特别强调, NutDao与NutIoc没有任何依赖关系, NutDao在NutIoc看来,只是普通的bean
		
	通过 Nutz.Ioc 的 XML 配置文件
		* 满足XML强迫症的程序猿, 功能与JSON配置文件类似
		
	再特别特别强调
		* NutDao几乎不需要任何配置文件(只有一个nutz_jdbc_experts.js 绝大部分时间你不会遇到它!)
		* 本文说到的js/xml文件,都是NutIoc的文件,不是NutDao的配置文件!!
		* 不要重复创建DataSource,不要重复创建NutDao!!!!!!!
		* 务必参考本小节末尾的提醒!!

--------------------------------------------------------------------------------------
内置的SimpleDataSource
	
	Nutz内置,非常适合新手!!无需额外下载其他连接池,方便尝试NutDao的功能.
		
		* 不要生产环境中使用这个DataSource!!
		* 不要用它来测试NutDao的性能!!
		* 自动加载NutDao所支持的数据库的驱动(说白了就是我们认识那几款,不就Class.forName一下嘛)
		* 无额外依赖,适合新手试用
		* 非连接池,配置简单
		* 1.b.43开始提供,旧版本的Nutz可通过拷贝源文件的方式添加这个类

	SimpleDataSource: 直接书写 Java 代码
		{{{<Java>
		import org.nutz.dao.impl.SimpleDataSource;
		
		...
		
		SimpleDataSource ds = new SimpleDataSource();
		//ds.setDriverClassName("org.postgresql.Driver"); //默认加载了大部分数据库的驱动!!
		ds.setJdbcUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUsername("demo");
		ds.setPassword("123456");
		...
		//ds.close();  // 这个DataSource不是一个连接池,所以关不关都行
		}}}
		
	SimpleDataSource: 通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
				type : "org.nutz.dao.impl.SimpleDataSource",
				fields : {
					jdbcUrl : 'jdbc:postgresql://localhost:5432/mydatabase',
					username : 'demo',
					password : '123456'
				}
			}
		}
		}}}
		
	SimpleDataSource: 通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="org.nutz.dao.impl.SimpleDataSource">
					<field name="jdbcUrl"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="username"><str>demo</str></field>
					<field name="password"><str>123456</str></field>
				</obj>
			</ioc>
		}}}
	
	附送一个完整的NutDao配置js文件
	
		{{{<IOC-JSON 配置>
		var ioc = {
			dao : {
				type : "org.nutz.dao.impl.NutDao",
				args : [{refer:"dataSource"}]
			},
			dataSource : {
				type : "org.nutz.dao.impl.SimpleDataSource",
				fields : {
					jdbcUrl : 'jdbc:postgresql://localhost:5432/mydatabase',
					username : 'demo',
					password : '123456'
				}
			}
		}
		}}}
		
	如何使用这些配置? 请看文章末尾.
--------------------------------------------------------------------------------------
Druid(推荐)

	国产精品连接池,淘宝温少诚意出品,带强大的监控功能哦
	
	druid : 直接书写 Java 代码
		{{{<Java>
		import com.alibaba.druid.pool.DruidDataSource;
		
		...
		
		DruidDataSource dds = new DruidDataSource();
        dds.setDriverClassName("org.postgresql.Driver");
        dds.setUrl("jdbc:postgresql://localhost:5432/mydatabase");
        dds.setUsername("enzozhong");
        dds.setPassword("123");
		...
		dds.close();  // 关闭池内所有连接
		}}}
	druid : 通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
                type : "com.alibaba.druid.pool.DruidDataSource",
                events : {
                    depose : 'close'
                },
                fields : {
                    driverClassName : "org.postgresql.Driver",
                    url : "jdbc:postgresql://localhost:5432/mydatabase",
                    username : "enzozhong",
                    password : "123",
                    maxWait: 15000, // 若不配置此项,如果数据库未启动,druid会一直等可用连接,卡住启动过程
                }
            }
		}
		}}}
	druid: 通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="com.alibaba.druid.pool.DruidDataSource">
					<events>
						<depose>close</depose>
					</events>
					<field name="driverClassName"><str>org.postgresql.Driver</str></field>
					<field name="url"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="username"><str>enzozhong</str></field>
					<field name="password"><str>123</str></field>
				</obj>
			</ioc>
		}}}
		 * 注册了 depose 事件，当整个 Ioc 容器注销时，将 {*真正 }  关闭所有池内连接
		 * [http://code.alibabatech.com/wiki/pages/viewpage.action?pageId=2916406 更多配置]
--------------------------------------------------------------------------------------
Apache Tomcat 7 连接池

	这里使用的是tomcat7新的自带连接,但是,请把其2个jar移到项目的lib中!!
	
	直接书写 Java 代码
		{{{<Java>
		import org.apache.tomcat.jdbc.pool.DataSource;
		
		...
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("org.postgresql.Driver");
		ds.setUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUsername("demo");
		ds.setPassword("123456");
		...
		ds.close();  // 关闭池内所有连接
		}}}
	通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
				type : "org.apache.tomcat.jdbc.pool.DataSource",
				events : {
					depose : 'close'
				},
				fields : {
					driverClassName : 'org.postgresql.Driver',
					url : 'jdbc:postgresql://localhost:5432/mydatabase',
					username : 'demo',
					password : '123456'
				}
			}
		}
		}}}
	通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="org.apache.tomcat.jdbc.pool.DataSource">
					<events>
						<depose>close</depose>
					</events>
					<field name="driverClassName"><str>org.postgresql.Driver</str></field>
					<field name="url"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="username"><str>demo</str></field>
					<field name="password"><str>123456</str></field>
				</obj>
			</ioc>
		}}}
		 * 注册了 depose 事件，当整个 Ioc 容器注销时，将 {*真正 }  关闭所有池内连接
		 * 关于 depose 事件，更多详情请参看 [../ioc/events.man 事件监听]
	
--------------------------------------------------------------------------------------
Apache DBCP
	dbcp: 直接书写 Java 代码
		{{{<Java>
		import org.apache.commons.dbcp.BasicDataSource;
		
		...
		
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName("org.postgresql.Driver");
		ds.setUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUsername("demo");
		ds.setPassword("123456");
		...
		ds.close();  // 关闭池内所有连接
		}}}
	dbcp: 通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
				type : "org.apache.commons.dbcp.BasicDataSource",
				events : {
					depose : 'close'
				},
				fields : {
					driverClassName : 'org.postgresql.Driver',
					url : 'jdbc:postgresql://localhost:5432/mydatabase',
					username : 'demo',
					password : '123456'
				}
			}
		}
		}}}
	dbcp: 通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="org.apache.commons.dbcp.BasicDataSource">
					<events>
						<depose>close</depose>
					</events>
					<field name="driverClassName"><str>org.postgresql.Driver</str></field>
					<field name="url"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="username"><str>demo</str></field>
					<field name="password"><str>123456</str></field>
				</obj>
			</ioc>
		}}}
		 * 注册了 depose 事件，当整个 Ioc 容器注销时，将 {*真正 }  关闭所有池内连接
		 * 关于 depose 事件，更多详情请参看 [../ioc/events.man 事件监听]
--------------------------------------------------------------------------------------
C3P0(不推荐)
	c3p0: 直接书写 Java 代码
		{{{<Java>
		import com.mchange.v2.c3p0.ComboPooledDataSource;
		
		...
		
		ComboPooledDataSource ds = new ComboPooledDataSource();
		ds.setDriverClass("org.postgresql.Driver");
		ds.setJdbcUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUser("demo");
		ds.setPassword("123456");
		...
		ds.close();  // 关闭池内所有连接
		}}}
	c3p0: 通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
				type : "com.mchange.v2.c3p0.ComboPooledDataSource",
				events : {
					depose : 'close'
				},
				fields : {
					driverClass : 'org.postgresql.Driver',
					jdbcUrl : 'jdbc:postgresql://localhost:5432/mydatabase',
					user : 'demo',
					password : '123456'
				}
			}
		}
		}}}
	c3p0: 通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="com.mchange.v2.c3p0.ComboPooledDataSource">
					<events>
						<depose>close</depose>
					</events>
					<field name="driverClass"><str>org.postgresql.Driver</str></field>
					<field name="jdbcUrl"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="user"><str>demo</str></field>
					<field name="password"><str>123456</str></field>
				</obj>
			</ioc>
		}}}
		 * 注册了 depose 事件，当整个 Ioc 容器注销时，将 {*真正 }  关闭所有池内连接
--------------------------------------------------------------------------------------
Proxool(严重不推荐)
	proxool: 直接书写 Java 代码
		{{{<Java>
		import org.logicalcobwebs.proxool.ProxoolDataSource;
		
		...
		
		ProxoolDataSource ds = new ProxoolDataSource();
		ds.setDriver("org.postgresql.Driver");
		ds.setDriverUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUser("demo");
		ds.setPassword("123456");
		...
		}}}
	proxool: 通过 Nutz.Ioc 的 JSON 配置文件
		{{{<IOC-JSON 配置>
		{
			dataSource : {
				type : "org.logicalcobwebs.proxool.ProxoolDataSource",
				fields : {
					driver : 'org.postgresql.Driver',
					driverUrl : 'jdbc:postgresql://localhost:5432/mydatabase',
					user : 'demo',
					password : '123456'
				}
			}
		}
		}}}
	proxool: 通过 Nutz.Ioc 的 XML 配置文件
		{{{<IOC-XML 配置>
			<ioc xsi:noNamespaceSchemaLocation="nutz-ioc-0.1.xsd">
				<obj name="dataSource" type="org.logicalcobwebs.proxool.ProxoolDataSource">
					<field name="driver"><str>org.postgresql.Driver</str></field>
					<field name="driverUrl"><str>jdbc:postgresql://localhost:5432/mydatabase</str></field>
					<field name="user"><str>demo</str></field>
					<field name="password"><str>123456</str></field>
				</obj>
			</ioc>
		}}}
		 * Proxool 没有提供关闭所有连接的函数，不过你可以参看它的官方文档，自己写一个释放所有连接的类，配置在 Ioc 容器的 depose 事件中
		 * 关于 depose 事件，更多详情请参看 [../ioc/events.man 事件监听] - {*通过实现一个触发器}

--------------------------------------------------------------------------------------
容器提供的连接池(JNDI)

	Java代码方式:
		不写了,这个大家都懂,不懂的自己去google查. 别跟我说baidu没查到!!
		
	由于是通过JNDI获取,所以不再是一个Ioc的bean, 我们只需要引用它就可以了,不需要再写dataSource的bean.例如:
		{{{<js>
		{
			dao : {
				type : "org.nutz.dao.impl.NutDao",
				args : [{jndi:"jdbc/dataSource"}]
			}
		}
		}}}
	
--------------------------------------------------------------------------------------
如何使用这些配置

	Java代码的方式:
		{{{<java>
		//创建dataSource,以DBCP为例, 代码仅供演示,实际使用的话必须单例
		DataSource ds = new BasicDataSource();
		ds.setDriverClassName("org.postgresql.Driver");
		ds.setUrl("jdbc:postgresql://localhost:5432/mydatabase");
		ds.setUsername("demo");
		ds.setPassword("123456");
		Dao dao = new NutDao(ds);
		
		dao.create(User.class, true);
		dao.insert(User.create("wendal","123456"));
		
		//.... ... ...
		
		//所有操作都已经完成,关闭连接池,退出系统
		ds.close();
		return;
		
		//额外提醒,NutDao是线程安全的,请不要多次创建NutDao,除非你有多个DataSource
		}}}
	
	通过 Nutz.Ioc 的 JSON 配置文件
		{{{<js>
		//将配置信息保存到dao.js,并存放于src文件夹下. 代码仅供演示,实际使用的话必须单例
		
		Ioc ioc = new NutIoc(new JsonLoader("dao.js"));
		DataSource ds = ioc.get(DataSource.class);
		Dao dao = new NutDao(ds); //如果已经定义了dao,那么改成dao = ioc.get(Dao.class);
		
		dao.create(User.class, true);
		dao.insert(User.create("wendal","123456"));
		
		ioc.depose(); //关闭Ioc容器
		}}}
		
	
	通过 Nutz.Ioc 的 XML 配置文件
		{{{
		//将配置信息保存到dao.xml,并存放于src文件夹下. 代码仅供演示,实际使用的话必须单例
		
		Ioc ioc = new NutIoc(new XmlIocLoader("dao.xml"));
		DataSource ds = ioc.get(DataSource.class);
		Dao dao = new NutDao(ds); //如果已经定义了dao,那么改成dao = ioc.get(Dao.class);
		
		dao.create(User.class, true);
		dao.insert(User.create("wendal","123456"));
		
		ioc.depose(); //关闭Ioc容器
		}}}
		
--------------------------------------------------------------------------------------
严重提醒

	* 上面提及的Java代码均为演示(main方法中的简单示例),实际用的时候, 必须将ioc容器本身单例化(例如存放到一个static属性)
	* 重复创建DataSource(例如反复创建ioc容器, new NutIoc(...))会导致数据库连接数耗尽!!
	* ioc容器本身,应该尽可能作为单例, 不要创建一个ioc容器后,获取ioc对象,然后就抛弃, 例如:
	
	绝对错误的用法
		{{{
		public Dao getDao() { // 无论改方法被调用一次还是N次, 均为错误!!
			Ioc ioc = new NutIoc(new JsonLoader("ioc/dao.js")); // 反复创建ioc容器
			return ioc.get(Dao.class); //方法返回后, ioc必然被gc, 从而触发ioc的depose事件,导致DataSource关闭!
		}
		}}}
		
	比较正确的用法
		{{{
		private static Ioc ioc;
		
		public Dao getDao() { // 暂不考虑线程同步的问题
			if (ioc == null)
				ioc = new NutIoc(new JsonLoader("ioc/dao.js")); 
			return ioc.get(Dao.class);
		}
		}}}
		
	Mvc中的正确用法,使用IocBy配置ioc,尽可能通过@Inject等方式获取ioc的bean.
	在无法直接获取Ioc容器的代码中,使用下列代码
		{{{
		// 在request作用域内
		public Dao getDao() {
			Mvcs.getIoc().get(Dao.class);
		}
		
		// 在request作用域之外
		public Dao getDao() {
			Mvcs.ctx().getDefaultIoc().get(Dao.class);
		}
		}}}
		